#ifndef AWESOMEMAN_H
#define AWESOMEMAN_H

#include "AReVi/arObject.h"
using namespace AReVi;

#include "hLib/hLib.h"
using namespace hLib;

#include "element.h"

/** An element with a 3D representation */
class AwesomeMan : public Element {
public:
    AR_CLASS(AwesomeMan)
    /*  Unable to differenciate local and distant object 
     *  Local by default */
    AR_CONSTRUCTOR(AwesomeMan)
    
    /** 3D Representation handling */
    inline virtual ArRef<Object3D> getRepresentation(void) const { return _representation; }

    /** Initialise element. Must be done after calling constructor.
     *  Can be used to differenciate local and distant elements */
    virtual void init();

    /** Retreive acceleration */
    double getAcceleration();
    /** Define acceleration */
    void setAcceleration(double acc);

    /** Retreive speed */
    double getSpeed();
    /** Define speed */
    void setSpeed(double speed);
    /** Retreive speed limits */
    void setSpeedLimits(double & min, double & max);
    /** Define speed limits */
    void setSpeedLimits(double min, double max);

    /** Retreive turn coefficient */
    double getTurnCoeff();
    /** Define turn coefficient (right < 0 < left) */
    void setTurnCoeff(double coeff); 

    /** Load animation and action data */
    static void loadAnimationAndActionData(StlString filename);

    /** Retreive a list of possible actions */
    StlVector<StlString> getActions();
    
    /** Retreive current action */
    StlString getAction();
    /** Retreive last action of stack */
    StlString getLastAction();
    /** Add an action to the stack.
     *  Will start has soon as possible */
    void doAction(StlString action);

protected:
    /** Write Element configuration to stream */
    virtual void writeConfiguration(ArRef<AbstractOStream> oStream);
    /** Read Element configuration to stream */
    virtual void readConfiguration(ArRef<AbstractIStream> iStream);

    /** Write Element configuration to stream */
    virtual void writeLocation(ArRef<AbstractOStream> oStream);
    /** Read Element configuration to stream */
    virtual void readLocation(ArRef<AbstractIStream> iStream);

    /** Write Element configuration to stream */
    virtual void writeUpdate(ArRef<AbstractOStream> oStream);
    /** Read Element configuration to stream */
    virtual void readUpdate(ArRef<AbstractIStream> iStream);

    /** To update location */
    virtual void updateLocation();

    /** Acceleration */
    double _acceleration;
    /** Speed */
    double _speed;
    /** Speed Limits */
    double _speedMin, _speedMax;

    /** Turn coefficient */
    double _turnCoeff;

    /** Visual representation */
    ArRef<Body> _representation;
    
    /** Class representing keyframe data for animation */
    struct KeyData {
        double time;
        StlString name;
        StlString pose;
    };

    /** Class representing animation data */
    struct AnimationData {
        StlString name;
        ArRef<Animation> animation;
        StlVector<AwesomeMan::KeyData *> keys;
    };

    /** Class representing action datas */
    struct ActionData {
        StlString name;
        AwesomeMan::AnimationData * animation;
        AwesomeMan::KeyData * begin;
        AwesomeMan::KeyData * end;
        bool cyclic;
    };
    
    /** Class representing the differents states of AwesomeMan */
    struct TransitionData;
    struct StateData {
        StlString name;
        StlVector<ActionData *> actions;
        StlVector<TransitionData *> transitions;
        bool cyclic;
        bool speedMin;
        double speedMinValue;
        bool speedMax;
        double speedMaxValue;
    };
    
    /** Class representing transitions */
    struct TransitionData {
        StateData *to;
        StlVector<ActionData *> actions;
    };
    
    /** Animations loaded for AwesomeMan */
    static StlVector<AwesomeMan::AnimationData *> _animations;
    /** Actions loaded for AwesomeMan */
    static StlVector<AwesomeMan::ActionData *> _actions;
    /** States loaded for AwesomeMan */
    static StlVector<AwesomeMan::StateData *> _states;
    /** Transitions loaded for AwesomeMan */
    static StlVector<AwesomeMan::TransitionData *> _transitions;

    /** Actions stack */
    StlVector<AwesomeMan::ActionData *> _actionStack;
    
    /** Animation offset */
    double _animationOffset;
    
    /** Actual pose name */
    StlString _pose;
};


#endif
